package com.xhlj.service.impl;

import com.alibaba.fastjson2.util.DateUtils;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhlj.entity.FileOss;
import com.xhlj.mapper.FileMapper;
import com.xhlj.service.FileService;
import com.xhlj.utils.OssResourcePath;
import com.xhlj.utils.Result;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.io.File;

@Service
public class FileServiceImpl extends ServiceImpl<FileMapper,FileOss> implements FileService{
    //引入配置文件中的自定义参数
    @Value("${aliyun.endPoint}")
    private String endPoint;
    @Value("${aliyun.keyId}")
    private String keyId;
    @Value("${aliyun.keySecret}")
    private String keySecret;
    @Value("${aliyun.bucketName}")
    private String bucketName;

    @Override
    public Result uploadFile(MultipartFile file,String fileDes,String folderName){
        try {
            //todo：文件不为空时进行文件云存储
            if (!file.isEmpty()) {
                // 创建OSSClient实例
                OSS ossClient = new OSSClientBuilder().build(endPoint, keyId, keySecret);
                // TODO:上传文件流
                InputStream inputStream = file.getInputStream();
                String originName = file.getOriginalFilename();
                //TODO:去掉后缀的文件名
                String nameWithoutExtension = originName.substring(0, originName.lastIndexOf("."));
                //TODO:后缀
                String extension=originName.substring(originName.lastIndexOf(".")+1);

                FileOss fileOss=new FileOss();
                fileOss.setFileName(nameWithoutExtension);
                fileOss.setFileExtension(extension);
                //生成日期前缀用于文件夹命名，此处先不使用
                String timeUrl = DateUtils.format(new Date(), "yyyy-MM-dd");

                //fileName 表示一个路径，文件夹名+生成的非重复文件名
                //生成随机唯一值，使用uuid，添加到文件名称里面
                String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                String fileName= uuid + originName;
                if(!Objects.equals(folderName, ""))
                {
                    fileName = folderName + "/"+ uuid + originName;
                }

                fileOss.setFileUrl(fileName);
                fileOss.setFileDownloadUrl("https://" + bucketName + "." + endPoint + "/" + fileName);
                fileOss.setFileFolder(folderName);
                fileOss.setFileDes(fileDes);

                //调用方法实现上传
                ossClient.putObject(bucketName, fileName, inputStream);

                //将新上传的文件信息加入数据库
                baseMapper.insert(fileOss);

                // 关闭OSSClient。
                ossClient.shutdown();
                //上传之后的完整文件路径
//                String url = "https://" + bucketName + "." + endPoint + "/" + fileName;
                //返回
                System.out.println("文件上传成功");
                Map<String,String> map=new HashMap<>();
                map.put("reply",originName+"文件上传成功");
                map.put("DownLoadUrl","https://" + bucketName + "." + endPoint + "/" + fileName);
                return Result.ok(map);
            }
            return Result.build(null,402,"文件上传失败");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //TODO:根据oss上的路径和本地路径将文件下载到本地
    @Override
    public Result downloadFile(Integer fileId,String localUrl) throws com.aliyuncs.exceptions.ClientException {
        //从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
       //TODO:根据id查询路径
        FileOss fileOss = baseMapper.selectById(fileId);
        String fileUrl=fileOss.getFileUrl();

        //TODO:指定默认的本地路径
        if(Objects.equals(localUrl, ""))
            localUrl="D:\\download\\"+fileOss.getFileName()+'.'+fileOss.getFileExtension();


        log.debug("localPath : " + localUrl);

        // TODO:创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint,  keyId, keySecret);
        try {
            // 下载Object到本地文件，并保存到指定的本地路径中。如果指定的本地文件存在会覆盖，不存在则新建。
            // 如果未指定本地路径，则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            OSSObject ossObject=ossClient.getObject(new GetObjectRequest(bucketName, fileUrl));
            //TODO:调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
            InputStream content = ossObject.getObjectContent();
            File file=new File(localUrl);
            if(!file.exists()){
             try {
                 file.getParentFile().mkdir();
                    //创建文件
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            copyInputStreamToFile(content,file);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return Result.ok("文件已下载到本地："+ localUrl);
    }

    // InputStream -> File
    private static void copyInputStreamToFile(InputStream inputStream, File file)
            throws IOException {
        try (FileOutputStream outputStream = new FileOutputStream(file)) {
            int read;
            byte[] bytes = new byte[1024];
            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }
            // commons-io
            //IOUtils.copy(inputStream, outputStream);
        }
    }

    //TODO：从bucket中获取文件列表，实际应用时只用读取file表数据，暂不考虑此方法
    @Override
    public Result getFileListFromOss() {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint,  keyId, keySecret);
        try {
            // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
            ObjectListing objectListing = ossClient.listObjects(bucketName);
            // objectListing.getObjectSummaries获取所有文件的描述信息。
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                System.out.println(" - " + objectSummary.getKey() + "  " +
                        "(size = " + objectSummary.getSize() + ")");
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    //TODO:根据文件id查找文件存储路径，在bucket中进行删除，删除成功后删除数据表中相应数据
    @Override
    public Result deleteFile(String fileId) {
        FileOss fileOss = baseMapper.selectById(fileId);
        String urlDelete=fileOss.getFileUrl();
        String fileName=fileOss.getFileName();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint,  keyId, keySecret);
        try {
            // 删除文件
            ossClient.deleteObject(bucketName, urlDelete);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        baseMapper.deleteById(fileId);
        return Result.ok("成功删除文件:"+fileName);
    }


    @Override
    public String toString() {
        return "FileServiceImpl{" +
                "endPoint='" + endPoint + '\'' +
                ", secretKey='" + keySecret + '\'' +
                ", keyId='" + keyId + '\'' +
                ", bucketName='" + bucketName + '\'' +
                '}';
    }
}
